﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;

namespace MoroMoro.Samples.ToDoList.Presentation.Utils
{
    /// <summary>
    /// 値と表示用テキストのペアで構成される ComboBox のデータソースを表します。
    /// </summary>
    /// <typeparam name="T">値の型。</typeparam>
    [Serializable]
    public sealed partial class ComboBoxDataSource<T> : Collection<ComboBoxDataSource<T>.DataItem>
    {
        /// <summary>
        /// <see cref="ComboBoxDataSource&lt;T&gt;"/> クラスの新しいインスタンスを初期化します。
        /// </summary>
        public ComboBoxDataSource()
        {
        }

        /// <summary>
        /// 元となる <see cref="DataItem"/> の一覧を指定して、<see cref="ComboBoxDataSource&lt;T&gt;"/> クラスの新しいインスタンスを初期化します。
        /// </summary>
        /// <param name="list"><see cref="DataItem"/> の一覧。</param>
        /// <exception cref="System.ArgumentNullException">list が null です。</exception>
        public ComboBoxDataSource(IList<DataItem> list)
            : base(list)
        {
        }

        /// <summary>
        /// 値の一覧と、値を表示用テキストに変換する変換メソッドを指定して、<see cref="ComboBoxDataSource&lt;T&gt;"/> クラスの新しいインスタンスを初期化します。
        /// </summary>
        /// <param name="values">値の一覧。</param>
        /// <param name="toString">値を表示用テキストに変換する変換メソッド。</param>
        /// <exception cref="System.ArgumentNullException">values または toString が null です。</exception>
        public ComboBoxDataSource(IEnumerable<T> values, Func<T, string> toString)
        {
            AddRange(values, toString);
        }
        

        /// <summary>
        /// 値と表示用テキストを元に <see cref="DataItem"/> を生成し追加します。
        /// </summary>
        /// <param name="value">値。</param>
        /// <param name="text">表示用テキスト。</param>
        public void Add(T value, string text)
        {
            Items.Add(new DataItem(value, text));
        }

        /// <summary>
        /// 値の一覧と、値を表示用テキストに変換する変換メソッドを元に <see cref="DataItem"/> の一覧を生成し追加します。
        /// </summary>
        /// <param name="values">値の一覧。</param>
        /// <param name="toString">値を表示用テキストに変換する変換メソッド。</param>
        /// <exception cref="System.ArgumentNullException">values または toString が null です。</exception>
        public void AddRange(IEnumerable<T> values, Func<T, string> toString)
        {
            if (values == null)
            {
                throw new ArgumentNullException("values");
            }
            if (toString == null)
            {
                throw new ArgumentNullException("toString");
            }

            foreach (var value in values)
            {
                Items.Add(new DataItem(value, toString(value)));
            }
        }

        /// <summary>
        /// <see cref="KeyValuePair&lt;TKey, TValue&gt;"/> で表される、値と表示用テキストのペアの一覧を元に、
        /// <see cref="DataItem"/> の一覧を生成し追加します。
        /// </summary>
        /// <param name="items">値と表示用テキストのペアの一覧</param>
        /// <exception cref="System.ArgumentNullException">items が null です。</exception>
        public void AddRange(IEnumerable<KeyValuePair<T, string>> items)
        {
            AddRange(items, item => item);
        }

        /// <summary>
        /// <see cref="KeyValuePair&lt;TKey, TValue&gt;"/> で表される、値と表示用テキストのペアの一覧を元に、
        /// <see cref="DataItem"/> の一覧を生成し追加します。
        /// </summary>
        /// <param name="items">値と表示用テキストのペアの一覧</param>
        /// <param name="converter">値の変換メソッド。</param>
        /// <exception cref="System.ArgumentNullException">items または converter が null です。</exception>
        public void AddRange<TKey>(IEnumerable<KeyValuePair<TKey, string>> items, Func<TKey, T> converter)
        {
            if (items == null)
            {
                throw new ArgumentNullException("items");
            }
            if (converter == null)
            {
                throw new ArgumentNullException("converter");
            }

            foreach (var item in items)
            {
                Items.Add(new DataItem(converter(item.Key), item.Value));
            }
        }
    }
}
